﻿using Net.Common;
using Net.Config;
using Net.Event;
using Net.Helper;
using Net.Share;
using Net.System;
using System;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using Cysharp.Threading.Tasks;

namespace Net.Client
{
    /// <summary>
    /// 分布式网络客户端(只用于分布式服务器之间连接通讯) 2025.2.14
    /// </summary>
    public abstract class Client : ClientUnitBase
    {
        /// <summary>
        /// IP地址
        /// </summary>
        public string Ip = "127.0.0.1";
        /// <summary>
        /// 端口号
        /// </summary>
        public int Port = 9543;
        /// <summary>
        /// 客户端配置
        /// </summary>
        public ClientConfig Config { get => (ClientConfig)(config ??= new ClientConfig()); set => config = value; }
        /// <summary>
        /// 网络FPS
        /// </summary>
        public int FPS { get; private set; }
        /// <summary>
        /// 网络独立执行线程
        /// </summary>
#if !UNITY_WEBGL
        protected Thread NetworkThread;
#endif
        /// <summary>
        /// 网络状态
        /// </summary>
        public NetworkState NetworkState { get; protected set; } = NetworkState.None;
        /// <summary>
        /// 当前客户端是否打开(运行)
        /// </summary>
        protected bool openClient;
        /// <summary>
        /// 客户端是否处于打开状态
        /// </summary>
        public bool IsOpenClient => openClient;

        #region 网络事件
        /// <summary>
        /// 当连接服务器成功事件
        /// </summary>
        public Action OnConnected { get; set; }
        /// <summary>
        /// 当连接失败事件
        /// </summary>
        public Action OnConnectFailed { get; set; }
        /// <summary>
        /// 当尝试连接服务器事件
        /// </summary>
        public Action OnTryToConnect { get; set; }
        /// <summary>
        /// 当尝试连接失败
        /// </summary>
        public Action TryToConnectFailed { get; set; }
        /// <summary>
        /// 当连接中断 (异常) 事件
        /// </summary>
        public Action OnConnectLost { get; set; }
        /// <summary>
        /// 当断开连接事件
        /// </summary>
        public Action OnDisconnect { get; set; }
        /// <summary>
        /// 当断线重连成功触发事件
        /// </summary>
        public Action OnReconnect { get; set; }
        /// <summary>
        /// 当关闭连接事件
        /// </summary>
        public Action OnCloseConnect { get; set; }
        /// <summary>
        /// 当统计网络流量时触发
        /// </summary>
        public NetworkDataTraffic OnNetworkDataTraffic { get; set; }
        /// <summary>
        /// 当排队等待中
        /// </summary>
        public Action<int, int> OnWhenQueuing { get; set; }
        /// <summary>
        /// 当排队解除调用
        /// </summary>
        public Action OnQueueCancellation { get; set; }
        /// <summary>
        /// 当服务器爆满，服务器积极拒绝客户端请求
        /// </summary>
        public Action OnServerFull { get; set; }
        /// <summary>
        /// 当更新版本(参数:服务器的版本号)-- 当服务器版本和客户端版本不一致时, 会调用此事件
        /// </summary>
        public Action<Version> OnUpdateVersion { get; set; }
        #endregion
        /// <summary>
        /// 上次的用户id, 断线重连时用到
        /// </summary>
        protected long PreUserId { get; set; }
        /// <summary>
        /// 客户端端口
        /// </summary>
        protected int localPort;
        /// <summary>
        /// 当前尝试重连次数
        /// </summary>
        public int CurrReconnect { get; protected set; }
        /// <summary>
        /// 网络更新方式
        /// </summary>
        public NetworkUpdateMode UpdateMode { get; set; } = NetworkUpdateMode.Thread;
        protected uint tokenCount = 1;
        protected FastLocking tokenLock = new();

        /// <summary>
        /// 构造函数
        /// </summary>
        public Client()
        {
            trafficStatistics = new();
        }

        ~Client()
        {
#if !UNITY_EDITOR || BUILT_UNITY
            Close();
#elif UNITY_EDITOR
            Close(true, 100);
#endif
        }

        /// <summary>
        /// 绑定网络状态处理接口
        /// </summary>
        /// <param name="network"></param>
        public override void BindEvent(INetworkHandle network)
        {
            OnConnected += network.OnConnected;
            OnConnectFailed += network.OnConnectFailed;
            OnConnectLost += network.OnConnectLost;
            OnDisconnect += network.OnDisconnect;
            OnReconnect += network.OnReconnect;
            OnTryToConnect += network.OnTryToConnect;
            OnCloseConnect += network.OnCloseConnect;
            OnWhenQueuing += network.OnWhenQueuing;
            OnQueueCancellation += network.OnQueueCancellation;
            OnServerFull += network.OnServerFull;
        }

        /// <summary>
        /// 移除网络状态处理接口
        /// </summary>
        /// <param name="network"></param>
        public override void UnBindEvent(INetworkHandle network)
        {
            OnConnected -= network.OnConnected;
            OnConnectFailed -= network.OnConnectFailed;
            OnConnectLost -= network.OnConnectLost;
            OnDisconnect -= network.OnDisconnect;
            OnReconnect -= network.OnReconnect;
            OnTryToConnect -= network.OnTryToConnect;
            OnCloseConnect -= network.OnCloseConnect;
            OnWhenQueuing -= network.OnWhenQueuing;
            OnQueueCancellation -= network.OnQueueCancellation;
            OnServerFull -= network.OnServerFull;
        }

        private void StartThread()
        {
#if !UNITY_WEBGL
            NetworkThread?.Interrupt();
            NetworkThread = new Thread(NetworkProcessing)
            {
                Name = "NetworkProcessing",
                IsBackground = true
            };
            NetworkThread.Start();
#endif
        }

        /// <summary>
        /// 连接服务器
        /// </summary>
        public UniTask<bool> Connect() => Connect(connected => { });

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="result">连接结果</param>
        /// <returns></returns>
        public UniTask<bool> Connect(Action<bool> result) => Connect(Ip, Port, result);

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        public virtual UniTask<bool> Connect(string ipAddress, int port) => Connect(ipAddress, port, result => { });

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        /// <param name="result">连接结果</param>
        public virtual UniTask<bool> Connect(string ipAddress, int port, Action<bool> result) => Connect(ipAddress, port, -1, result);

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        /// <param name="localPort">设置自身端口号,如果不设置自身端口则值为-1</param>
        /// <param name="result">连接结果</param>
        public virtual UniTask<bool> Connect(string ipAddress, int port, int localPort, Action<bool> result)
        {
            if (UpdateMode == NetworkUpdateMode.Thread)
                StartThread();
            if (NetworkState == NetworkState.Connection)
            {
                NDebug.Log("连接服务器中,请稍等...");
                return UniTask.FromResult(false);
            }
            if (openClient)
            {
                Close();
                NDebug.Log("连接服务器中,请稍等...");
            }
            openClient = true;
            NetworkState = NetworkState.Connection;
            OnRpcInvoke ??= DispatchRpc;
            if (Client == null) //如果套接字为空则说明没有连接上服务器
            {
                Ip = ipAddress;
                Port = port;
                if (IPAddress.TryParse(Ip, out var address)) //如果ip是域名则出现问题处理
                    RemotePoint = new IPEndPoint(address, Port);
                return ConnectResult(ipAddress, port, localPort, result);
            }
            else if (!Connected)
            {
                Client.Close();
                Client = null;
                NetworkState = NetworkState.ConnectLost;
                RpcAdapter.WorkerQueue.Call(OnConnectLost);
                NDebug.LogError($"连接{RemotePoint}中断!");
                result(false);
            }
            else
            {
                result(true);
            }
            return UniTask.FromResult(Connected);
        }

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="ipAddress">连接的服务器主机IP地址</param>
        /// <param name="port">连接的服务器主机端口号</param>
        /// <param name="localPort">设置自身端口号,如果不设置自身端口则值为-1</param>
        /// <param name="result">连接结果</param>
        protected virtual async UniTask<bool> ConnectResult(string ipAddress, int port, int localPort, Action<bool> result)
        {
            try
            {
                OnCreateSocket(ipAddress, port);
                OnBindSocketEndPoint(localPort);
                OnSocketConnect(ipAddress, port);
                SendHandshake();
                await UniTaskNetExtensions.Wait(NetworkLoop, 8000, (state) => UserId != 0 || !openClient, DBNull.Value); //如果在爆满事件关闭客户端就需要判断一下
                if (UserId == 0 && openClient)
                    throw new Exception("连接握手失败!");
                if (UserId == 0 && !openClient)
                    throw new Exception("客户端调用Close!");
                Connected = true;
                NetworkInitialize();
            }
            catch (Exception ex)
            {
                NDebug.LogError("连接错误:" + ex);
                Connected = false;
                Client?.Close();
                Client = null;
            }
            OnConnectedHandler(Connected, result);
            await UniTask.Yield(); //切回主线程执行
            return Connected;
        }

        protected virtual void OnBindSocketEndPoint(int localPort)
        {
            this.localPort = localPort;
            if (localPort != -1)
                Client.Bind(new IPEndPoint(IPAddress.Any, localPort));
        }

        protected virtual void OnCreateSocket(string ipAddress, int port)
        {
            Client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
            {
                SendBufferSize = config.SendBufferSize,
                ReceiveBufferSize = config.ReceiveBufferSize
            };
        }

        protected virtual void SendHandshake()
        {
            var segment = BufferPool.Take(Config.SendBufferSize);
            segment.Write(PreUserId);
            Client.Send(segment.ToArray(true));
        }

        protected virtual void OnSocketConnect(string ipAddress, int port) => Client.Connect(ipAddress, port);

        internal protected override void NetworkInitialize()
        {
            NetworkLoop.RemoveEvent(networkFlowHandlerID);
            networkFlowHandlerID = NetworkLoop.AddEvent("NetworkFlowHandler", 1f, NetworkFlowHandler);
            base.NetworkInitialize();
        }

        /// <summary>
        /// 连接结果处理
        /// </summary>
        /// <param name="isConnect"></param>
        /// <param name="action">结果</param>
        protected void OnConnectedHandler(bool isConnect, Action<bool> action)
        {
            if (isConnect)
            {
                NetworkState = NetworkState.Connected;
                RpcAdapter.WorkerQueue.Call(action, true);
                RpcAdapter.WorkerQueue.Call(OnConnected);
                NDebug.Log($"连接{RemotePoint}成功!");
            }
            else
            {
                NetworkState = NetworkState.ConnectFailed;
                RpcAdapter.WorkerQueue.Call(action, false);
                RpcAdapter.WorkerQueue.Call(OnConnectFailed);
                NDebug.LogError($"连接{RemotePoint}失败!");
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="reuseSocket">断开连接后还能重新使用？</param>
        /// <param name="invokeSocketDisconnect"></param>
        public virtual void Disconnect(bool reuseSocket, bool invokeSocketDisconnect = true)
        {
            NetworkState = NetworkState.Disconnect;
            Call(NetCmd.Disconnect, new byte[1]);
            SendDirect();
            OnNetworkTick(); //udp需要update发送
            Connected = false;
            if (Client != null && Client.ProtocolType == ProtocolType.Tcp && invokeSocketDisconnect)
                Client.Disconnect(reuseSocket);
            RpcAdapter.WorkerQueue.Call(OnDisconnect);
        }

        /// <summary>
        /// 调式输出网络流量信息
        /// </summary>
        protected virtual bool NetworkFlowHandler()
        {
            try
            {
                trafficStatistics.TotalSentBytes += trafficStatistics.SentBytesPerSecond;
                trafficStatistics.TotalReceivedBytes += trafficStatistics.ReceivedBytesPerSecond;
                trafficStatistics.FrameRate = FPS;
                OnNetworkDataTraffic?.Invoke(trafficStatistics);
            }
            catch (Exception ex)
            {
                NDebug.LogError(ex.ToString());
            }
            finally
            {
                trafficStatistics.SentBytesPerSecond = 0;
                trafficStatistics.SentPacketsPerSecond = 0;
                trafficStatistics.RpcResolveCount = 0;
                trafficStatistics.ReceivedPacketsPerSecond = 0;
                trafficStatistics.ReceivedBytesPerSecond = 0;
                FPS = 0;
            }
            return Connected;
        }

        protected virtual void NetworkProcessing()
        {
            while (openClient)
            {
                NetworkTick(16, true);
            }
        }

        public virtual void Update()
        {
            if (!openClient) //如果被服务器强制断开, 则不需要触发重连了
                return;
            if (UpdateMode == NetworkUpdateMode.Custom)
                NetworkTick();
            else
                RpcAdapter.Execute();
        }

        protected virtual void NetworkTick(uint interval = 16, bool sleep = false)
        {
            try
            {
                NetworkLoop.FixedUpdate(interval, sleep);
                ReceiveHandler();
                SendDirect();
                OnNetworkTick();
                FPS++;
            }
            catch (Exception ex)
            {
                NDebug.LogError("网络异常:" + ex);
            }
        }

        public override void ConnectLost(SocketError socketError)
        {
            Connected = false;
            KeepAliveCount = 0;
            NetworkState = NetworkState.ConnectLost;
            RpcAdapter.WorkerQueue.Call(OnConnectLost);
            SetKeepAliveTimeout(Config.ReconnectInterval); //断线后, 会改变心跳时间为断线重连间隔时间
            NDebug.LogError($"[{this}]连接中断!");
        }

        protected override bool IsDeserialize(byte cmd) => true;

        protected override void OnCommand3Handler(IRpcModel model, ISegment segment)
        {
            switch (model.Cmd)
            {
                case NetCmd.ConnectHash:
                    Connected = true;
                    break;
                case NetCmd.IdentifyHash:
                    UserId = PreUserId = segment.ReadInt64();
                    if (segment.Position >= segment.Count) //此代码是兼容旧版本写法
                        return;
                    var adapterType = segment.ReadString();
                    var versionPacked = segment.ReadInt32();
                    int major = (versionPacked >> 24) & 0xFF;
                    int minor = (versionPacked >> 16) & 0xFF;
                    int build = (versionPacked >> 8) & 0xFF;
                    int revision = versionPacked & 0x0FF;
                    Version version;
                    if (build == 255)
                        version = new Version(major, minor);
                    else if (revision == 255)
                        version = new Version(major, minor, build);
                    else
                        version = new Version(major, minor, build, revision);
                    if (version != config.Version)
                        RpcAdapter.WorkerQueue.Call(OnUpdateVersion, version);
                    if (string.IsNullOrEmpty(adapterType))
                        return;
                    var type = AssemblyHelper.GetType(adapterType);
                    var adapter = (ISerializeAdapter)Activator.CreateInstance(type);
                    AddAdapter(adapter);
                    break;
                case NetCmd.QueueUpHash:
                    {
                        var totalCount = segment.ReadInt32();
                        var queueUpCount = segment.ReadInt32();
                        RpcAdapter.WorkerQueue.Call(OnWhenQueuing, totalCount, queueUpCount);
                    }
                    break;
                case NetCmd.QueueCancellationHash:
                    RpcAdapter.WorkerQueue.Call(OnQueueCancellation);
                    break;
                case NetCmd.ServerFullHash:
                    RpcAdapter.WorkerQueue.Call(OnServerFull);
                    break;
                default:
                    base.OnCommand3Handler(model, segment);
                    break;
            }
        }

        /// <inheritdoc/>
        protected override void OnReceiveDataHandler(IRpcModel model, ISegment segment)
        {
            if (model.Protocol != 0)
                OnRpcHandler(model);
            else
                OnReceiveData?.Invoke(model);
        }

        /// <summary>
        /// 后台线程发送心跳包
        /// </summary>
        protected override bool KeepAliveHandler()
        {
            if (!Connected)
                InternalReconnection();//尝试连接执行
            else if (Environment.TickCount > KeepAliveTimeout)
            {
                Call(NetCmd.KeepAlive, new byte[1]);
                if (KeepAliveCount++ >= Config.KeepAliveCount) //udp协议如果断开是不知道的, 也不会发出异常, 所以如果在保活期内没有回应则说明断线了
                {
                    ConnectLost(SocketError.Disconnecting);
                }
            }
            return openClient & CurrReconnect < Config.ReconnectCount;
        }

        /// <summary>
        /// 内部断线重新连接
        /// </summary>
        protected virtual void InternalReconnection()
        {
            if (!Config.AutoReconnecting)
                return;
            Reconnection();
        }

        /// <summary>
        /// 断线重新连接
        /// </summary>
        public void Reconnection()
        {
            if (NetworkState == NetworkState.Connection || NetworkState == NetworkState.TryToConnect ||
                NetworkState == NetworkState.ConnectClosed || NetworkState == NetworkState.Reconnect)
                return;
            if (CurrReconnect >= Config.ReconnectCount)//如果想断线不需要重连,则直接返回
            {
                NetworkState = NetworkState.ConnectFailed;
                RpcAdapter.WorkerQueue.Call(OnConnectFailed);
                Close();
                NDebug.LogError($"连接{RemotePoint}失败,请检查网络是否异常!(无重连次数)");
                return;
            }
            Client?.Close();
            UserId = 0;
            CurrReconnect++;
            NetworkState = NetworkState.TryToConnect;
            SetKeepAliveTimeout(Config.ReconnectInterval);
            RpcAdapter.WorkerQueue.Call(OnTryToConnect);
            NDebug.Log($"尝试重连{RemotePoint}({CurrReconnect})");
            _ = ConnectResult(Ip, Port, localPort, OnReconnectConnected);
        }

        private void OnReconnectConnected(bool isConnect)
        {
            if (!openClient)
                return;
            if (isConnect)
            {
                CurrReconnect = 0;
                KeepAliveCount = 0;
                NetworkState = NetworkState.Reconnect;
                RpcQueue = new();
                SetKeepAliveTimeout(config.KeepAliveTimeout);
                RpcAdapter.WorkerQueue.Call(OnReconnect);
                NDebug.Log($"重连{RemotePoint}成功!");
            }
            else if (CurrReconnect >= Config.ReconnectCount)//尝试maxFrequency次重连，如果失败则退出线程
            {
                NetworkState = NetworkState.ConnectFailed;
                RpcAdapter.WorkerQueue.Call(OnConnectFailed);
                Close();
                NDebug.LogError($"连接{RemotePoint}失败,请检查网络是否异常!");
            }
            else
            {
                NetworkState = NetworkState.TryToConnectFailed;
                RpcAdapter.WorkerQueue.Call(TryToConnectFailed);
            }
        }

        /// <inheritdoc/>
        public override void Close()
        {
            base.Close();
            Close(true, 100);
        }

        /// <summary>
        /// 关闭连接,释放线程以及所占资源
        /// </summary>
        /// <param name="isWait">true:等待内部1秒结束所有线程再关闭? false:直接关闭</param>
        /// <param name="millisecondsTimeout">等待毫秒数</param>
        public virtual void Close(bool isWait = true, int millisecondsTimeout = 100)
        {
            var isDispose = openClient;
            if (Connected & openClient & NetworkState == NetworkState.Connected)
                Disconnect(false, false);
            Connected = false;
            openClient = false;
            NetworkState = NetworkState.ConnectClosed;
            RpcAdapter.WorkerQueue.Call(OnCloseConnect);
            if (isWait) Thread.Sleep(millisecondsTimeout);//给update线程一秒的时间处理关闭事件
#if !UNITY_WEBGL
            NetworkThread?.Interrupt();
#endif
            Client?.Close();
            Client = null;
            RpcQueue = new();
            overlapPackStream?.Dispose();
            overlapPackStream = null;
            overlapPack = 0;
            overlapPackOffset = 0;
            overlapPackLength = 0;
            UserId = 0;
            PreUserId = 0;
            CurrReconnect = 0;
            if (isDispose) NDebug.Log("客户端关闭成功!"); //只有打开状态下才会提示
        }

        #region 同步远程调用, 跟Http协议一样, 请求必须有回应 请求和回应方法都是相同的, 都是根据protocol请求和回应
        public UniTask<RpcModelAsync> Request(uint protocol, params object[] pars)
            => Request(NetCmd.CallRpc, protocol, RequestTimeout.FiveSeconds, true, SyncSerialize.False, null, pars);
        public UniTask<RpcModelAsync> Request(uint protocol, in RequestTimeout timeout, params object[] pars)
            => Request(NetCmd.CallRpc, protocol, timeout, true, SyncSerialize.False, null, pars);
        public UniTask<RpcModelAsync> Request(uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
            => Request(NetCmd.CallRpc, protocol, timeout, intercept, SyncSerialize.False, null, pars);
        public UniTask<RpcModelAsync> Request(NetCmd cmd, uint protocol, in RequestTimeout timeout, params object[] pars)
            => Request(cmd, protocol, timeout, true, SyncSerialize.False, null, pars);
        public UniTask<RpcModelAsync> Request(NetCmd cmd, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
            => Request(cmd, protocol, timeout, intercept, SyncSerialize.False, null, pars);
        #endregion

        public virtual async UniTask<RpcModelAsync> Request(NetCmd cmd, uint protocol, RequestTimeout timeout, bool intercept, SyncSerialize serialize, byte[] buffer, params object[] pars)
        {
            tokenLock.Enter();
            var requestTask = new RpcModelAsync();
            var methodList = RpcAdapter.GetOrAddRpcMethodList(protocol);
            var token = tokenCount++;
            while (token == 0)
                token = tokenCount++;
            Call(cmd, protocol, true, serialize, new RequestToken(token), buffer, pars);
            if (timeout.Timeout == 0U)
                timeout = RequestTimeout.FiveSeconds;
            requestTask.Intercept = intercept;
            var addResult = methodList.Requests.TryAdd(token, requestTask);
            if (!addResult)
                NDebug.LogError($"请求Token添加失败! token:{token}");
            tokenLock.Exit();
            await UniTaskNetExtensions.WaitCallback(NetworkLoop, (int)timeout.Timeout, requestTask);
            if (!requestTask.IsCompleted)
                methodList.Requests.Remove(token);
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
            await UniTaskNetExtensions.SwitchToMainThread(RpcAdapter.WorkerQueue);
#else
            await UniTaskNetExtensions.SwitchToNetThreadPool();
#endif
            return requestTask;
        }

        /// <summary>
        /// ping测试网络延迟, 通过<see cref="OnPingCallback"/>事件回调
        /// </summary>
        public void Ping()
        {
            uint tick = (uint)Environment.TickCount;
            Call(NetCmd.Ping, BitConverter.GetBytes(tick));
        }

        /// <summary>
        /// ping测试网络延迟, 此方法帮你监听<see cref="OnPingCallback"/>事件, 如果不使用的时候必须保证能移除委托, 建议不要用框名函数, 那样会无法移除委托
        /// </summary>
        /// <param name="callback"></param>
        public void Ping(Action<uint> callback)
        {
            uint tick = (uint)Environment.TickCount;
            Call(NetCmd.Ping, BitConverter.GetBytes(tick));
            OnPingCallback += callback;
        }

        /// <summary>
        /// 添加网络状态事件处理
        /// </summary>
        /// <param name="listen">要监听的网络状态</param>
        /// <param name="action">监听网络状态的回调方法</param>
        public void AddStateHandler(NetworkState listen, Action action)
        {
            switch (listen)
            {
                case NetworkState.Connected:
                    OnConnected += action;
                    break;
                case NetworkState.ConnectFailed:
                    OnConnectFailed += action;
                    break;
                case NetworkState.ConnectLost:
                    OnConnectLost += action;
                    break;
                case NetworkState.Reconnect:
                    OnReconnect += action;
                    break;
                case NetworkState.ConnectClosed:
                    OnCloseConnect += action;
                    break;
                case NetworkState.Disconnect:
                    OnDisconnect += action;
                    break;
                case NetworkState.TryToConnect:
                    OnTryToConnect += action;
                    break;
                case NetworkState.OnWhenQueuing:

                    break;
                case NetworkState.OnQueueCancellation:
                    OnQueueCancellation += action;
                    break;
            }
        }

        /// <summary>
        /// 检查send方法的发送队列是否已到达极限, 到达极限则不允许新的数据放入发送队列, 需要等待队列消耗后才能放入新的发送数据
        /// </summary>
        /// <returns>是否可发送数据</returns>
        public bool CheckCall()
        {
            return RpcQueue.Count < config.LimitQueueCount;
        }

        /// <inheritdoc/>
        public override void Dispose()
        {
            base.Dispose();
            Close();
        }

        /// <summary>
        /// 当设置配置信息
        /// </summary>
        /// <param name="args"></param>
        public virtual void OnSetConfigInfo(params object[] args)
        {
        }

        /// <summary>
        /// 设置配置
        /// </summary>
        /// <param name="config"></param>
        public void SetConfig(ClientConfig config)
        {
            if (config == null)
                return;
            base.config = config;
        }

        public override string ToString()
        {
            return $"用户ID:{UserId} IP:{Ip}:{Port}";
        }
    }
}